#ifndef GAMESERVER_H
#define GAMESERVER_H

#include "Game/GameCore.h"

#include "Game/SocketDefine.h"
#include "Game/GameDefine.h"

#include "_Global/Server/Server.h"
#include "_Global/Mysql/Mysql.h"

#include <QHash>


#define WAIT_GAME_TERMINATE_TIME 5000


//数据库交换类    !!!注意注入!!!
class _GameUserData;
class DatabaseSwap : public Mysql
{
    Q_OBJECT
public:
    explicit DatabaseSwap(QObject *parent = nullptr);
    virtual ~DatabaseSwap();


public:
    //[ok!]
    //查询用户,参数为 pClientInfo的m_strUserName 和 密码,找到后 设置 pClientInfo的id
    //返回0:成功,1:用户名不对,2:密码不对;<0:服务器/数据库错误
    int queryUser(_ClientInfo *pClientInfo, QString password);

    //[ok!]
    //注册用户
    //返回1:注册失败(重名),0:成功,<0:服务器/数据库错误
    int registerUser(_ClientInfo *pClientInfo, QString password);

    //[ok!]
    //将 所有服务器信息 放入Buffer中
    //返回0:成功,<0:服务器/数据库错误
    int getGameServerInfoToBuffer(QDataStream &out);

    //[ok!]
    //将 玩家游戏账户信息 放入Buffer中
    //返回0:成功,1:没有游戏账户信息,<0:服务器/数据库错误
    int getGameUserInfoToBuffer(QDataStream &out, quint32 userID, quint32 serviceID, quint32 gradeID, QString serverKey, _ClientInfo *pClientInfo);

    //[ok!]
    //将 课程信息 放入Buffer中
    //返回0:成功,<0:服务器/数据库错误
    int getGameClassInfoToBuffer(QDataStream &out);

    //[ok!]
    //将 用户学习信息 放入Buffer中
    //返回0:成功,<0:服务器/数据库错误
    int getGameUserStudyInfoToBuffer(QDataStream &out, quint32 userGameID);

    //[ok!]
    //将 排名信息 放入Buffer中
    //返回0:成功,<0:服务器/数据库错误
    int getGameUserRankingToBuffer(QDataStream &out, quint32 serverID, quint32 gradeID);

    int getGameUserItemsToBuffer(QDataStream &out, _GameUserData* pGameUserData, quint32 serverID);

    //[ok!]
    //注册 用户游戏信息,并将结果放入Buffer
    //返回0:成功,1:信息重复,<0:服务器/数据库错误
    int registerGameUser(quint32 userID, quint32 serverID, QString nickName, qint16 sex, QDataStream &out, _ClientInfo *pClientInfo);

    //[ok!]
    //保存 用户学习记录,newLevel:新建一个记录
    //返回0是Update,返回1是Insert,<0:服务器/数据库错误
    qint16 saveUserStudyResult(quint32 userGameID
                            , quint32 classID, quint32 levelID
                            , QString result);

    //[ok!]
    //更新 用户金币
    //返回0是成功,<0:服务器/数据库错误
    int updateUserScore(quint32 userGameID, qint32 scoreAdd);


public:
    //插入 用户登录登出记录
    int insertUserOnlineLog(quint32 userGameID, qint16 clientType, QDateTime dtLogin, QDateTime dtLogout);


private:
    //QStringList strlistSqlQuery;    //查询语句
};







//游戏登录后 用户数据
struct _GameUserData
{
public:
    explicit _GameUserData():
        m_GameStatus(_ClientGameStatus::Game_Nothing),
        m_unID(0),
        m_nGradeID(0),
        m_unUserGameID(0),
        m_nSex(-1),
        m_nDuiWu(-1),
        m_nPlayID(-1)
    {
        //_pool_init();
    }
    virtual ~_GameUserData()
    {}

    virtual void _pool_init()
    {
        qDebug() << "[GameServer]_GameUserData _pool_init";
    }
    virtual void _pool_release()
    {
        qDebug() << "[GameServer]_GameUserData _pool_release";

        m_GameStatus = _ClientGameStatus::Game_Nothing;

        m_unID = 0;
        m_nGradeID = 0;
        m_unUserGameID = 0;
        m_nSex = -1;
        m_nDuiWu = -1;
        m_nPlayID = -1;

        m_strUserName.clear();
        m_strNickName.clear();
    }

public:
    //切换用户ready状态:Game_Waiting和Game_Readying切换返回0,其他返回-1
    int ChangeGameStatus()
    {
        if(m_GameStatus == _ClientGameStatus::Game_Waiting)
            m_GameStatus = _ClientGameStatus::Game_Readying;
        else if(m_GameStatus == _ClientGameStatus::Game_Readying)
            m_GameStatus = _ClientGameStatus::Game_Waiting;
        else
            return -1;
        return 0;
    }
    void ChangeGameStatus(_ClientGameStatus status)
    {
        m_GameStatus = status;
    }

public:
    _ClientGameStatus   m_GameStatus;     //玩家房间内状态

//Info数据
    quint32 m_unID;         //客户id(数据库的id号)//void *m_id;
    QString m_strUserName;
    quint32 m_nGradeID;     //学业

//GameInfo数据
    quint32 m_unUserGameID; //客户游戏号
    QString m_strNickName;
    qint16  m_nSex;

    //int login;            //登录状态,目前没用
    //QString password;

//游戏数据
    qint16 m_nDuiWu;
    qint16 m_nPlayID;       //游戏player的下标

};


//群,重写GameCore
class _GameGroup: public GameCore
{
    Q_OBJECT
public:
    explicit _GameGroup(QObject *parent = nullptr)
        :GameCore(parent)
    {
        m_pClientsGroupInfo = nullptr;
        //InitOnce();
        m_nGroupID = -1;
        //_pool_init();
        _pool_bNew = true;
    }
    virtual ~_GameGroup()
    {
        TerminateGame(-1, GameCore::Game_Status_Terminated);
        if(isRunning())
        {
            //!!!注意这里,是否需要等待!!!
            if(!wait(WAIT_GAME_TERMINATE_TIME))  //返回true:线程已经退出
            {
                terminate();
            }
            emit s_GameOver(gameStatus());
        }
        //_release();
    }

public:
    virtual void _pool_init()
    {
        qDebug() << "[GameServer]_GameGroup _pool_init";
        if(isRunning())
        {
            terminate();
            emit s_GameOver(gameStatus());
        }
    }
    virtual void _pool_release()
    {
        qDebug() << "[GameServer]_GameGroup _pool_release";
        m_nGroupID = -1;
        TerminateGame(-1, GameCore::Game_Status_Terminated);
        //this->disconnect();
    }

    //设置为 旧节点(不是新new的)
    virtual void _pool_setNewNode(bool bNew = false)
    {
        _pool_bNew = bNew;
    }
    //是否为new节点
    virtual bool _pool_newNode()
    {
        return _pool_bNew;
    }
    bool _pool_bNew;    //是否是new出来的节点(有些地方可能需要初始化一下)

signals:
    //GameCore线程中使用信号来发送
    void s_SendToGroupAllClients(QByteArray ba, _ClientInfo *pClientInfo);


//服务器函数(主线程)
public:
    //外部初始化,并给客户端发送初始化数据
    //0:正常;-1:玩家为空!;-2:已经在玩!;-3:有人没准备好!
    int StartGame();
    void OverGame(GameCore::_GameStatus ret)
    {
        emit s_Debug(_T("[GameGroup]游戏%1结束:%2").arg(m_pClientsGroupInfo->m_uuid.toString()).arg(ret));

        m_pClientsGroupInfo->m_flagStatus = _ClientsGroupInfo::Status_Normal;

        QList<_ClientInfo*>::const_iterator ii;
        for(ii = m_pClientsGroupInfo->m_listClients.constBegin(); ii != m_pClientsGroupInfo->m_listClients.constEnd(); ++ii)
        {
            ((_GameUserData*)((*ii)->m_pClientExtraData))->m_GameStatus = _ClientGameStatus::Game_Waiting;
        }
    }

    //封装_ClientsGroupInfo::SendToGroupAllClients
    int SendToGroupAllClients(QByteArray ba, _ClientInfo *pClientInfo = nullptr)
    {
        if(m_pClientsGroupInfo != nullptr)
            return m_pClientsGroupInfo->SendToGroupAllClients(ba, pClientInfo);
        return -1;
    }


//线程执行
public:

    //创建问题并发送
    bool Game_CreateWenTiAndSend(qint32 wordID[4], qint16 nAnswer);

//重载线程函数:
public:
    //一次初始化
    virtual int InitOnce() Q_DECL_OVERRIDE
    {
        qDebug() << "[GameGroup]InitOnce";
        return GameCore::InitOnce();
    }

    //GameCore初始化
    virtual int GameInit(int sr = -1) Q_DECL_OVERRIDE
    {
        qDebug() << "[GameGroup]GameInit";
        //m_mutexUserAction.tryLock();
        //m_mutexNet.tryLock();
        //releaseDataList();

        /*
        while(!dataList.isEmpty())
        {
            delete dataList.takeFirst();
        }*/
        m_Producer.init();

        return GameCore::GameInit(sr);
    }


    //游戏结束,由GameCore调用
    virtual int GameOver() Q_DECL_OVERRIDE;

    //强制结束游戏,并群发给所有客户
    virtual void TerminateGame(int ret, _GameStatus status = Game_Status_Exit) Q_DECL_OVERRIDE
    {
        //!!!注意:因为游戏退出,不一定会真正将线程结束(因为有些函数返回Game_Button_Err!!!)
        //if(gameStatus() != Game_Status_Continue)
        //    return;

        //先暂时用这个判断!!!
        if(!this->isRunning())
            return;

        GameCore::TerminateGame(ret, status);

        m_Producer.comingNetDataSemaphore();


        quit();
        /*
        if(!wait(WAIT_GAME_TERMINATE_TIME))  //返回true:线程已经退出
        {
            terminate();
        }*/


        //发送
        QByteArray ba = m_pClientsGroupInfo->m_pIOCP->newSendData(0x10);
        QDataStream ds(&ba,QIODevice::ReadWrite);
        ds.device()->seek(ba.size());
        ds << (qint16)GAME_SERVER_RESPONSE
           << (qint16)GAME_SERVER_GAMEOVER
           << (qint16)ret
           //<< playerJiaoSeList
              ;
        m_pClientsGroupInfo->m_pIOCP->CorrectDataLength(ba);
        m_pClientsGroupInfo->SendToGroupAllClients(ba, nullptr);
        //sl_UserActionFinished();
    }


//重载逻辑:
public:
    GameCore::_GameStatus ChoiceWuJiang(int count) Q_DECL_OVERRIDE
    {
        GameCore::ChoiceWuJiang(count);

        int userCount = m_pClientsGroupInfo->m_listClients.count();
        while(1)
        {
            emit s_Debug("[GameServer]等待玩家选择武将");
            _GameData *pData = (_GameData*)m_Producer.safeOut();
            if(CheckGameOver() != Game_Status_Continue)
            {
                if(pData != nullptr)
                    delete pData;
                return setGameStatus(Game_Status_ERROR);
            }

            if(pData == nullptr)
            {
                emit s_Critical(_T("[!GameServer]选择武将同步ERROR:pData为nullptr"));
                return setGameStatus(Game_Status_ERROR);
            }
            if(pData->type != GAME_DATA_TRANSFER_CHOICEWUJIANG)
            {
                emit s_Critical(_T("[!GameGroup]选择武将同步ERROR:类型错误(%1)").arg(pData->type));
                delete pData;
                return setGameStatus(Game_Status_ERROR);
            }
            /*if(((_GameUserData*)((_ClientInfo*)pData->sender)->m_pClientExtraData)->m_nPlayID != player)
            {
                emit s_Critical(_T("[!GameGroup]选择武将同步ERROR:发送者错误:(%1,%2)")
                      .arg(((_GameUserData*)((_ClientInfo*)pData->sender)->m_pClientExtraData)->m_nPlayID)
                      .arg(player)
                      );
                delete pData;
                return setGameStatus(Game_Status_ERROR);
            }*/
            delete pData;


            int i;
            for(i = 0; i < m_nPlayerCount; i++)
            {
                if(m_arrayPlayer[i].m_eJiaoSe == _Player::JiaoSe_Others)       //是 玩家
                {
                    //_GameUserData* m_pClientExtraData = (_GameUserData*)(m_pClientsGroupInfo->m_listClients.at(i)->m_pClientExtraData);
                    if(m_arrayPlayer[i].wuJiangValue() == _WuJiang::Value_Null)
                        break;
                }
                else if(m_arrayPlayer[i].m_eJiaoSe == _Player::JiaoSe_AI)    //是电脑
                {
                    continue;
                }
                else
                {
                    emit s_Critical("[!GameServer]电脑选择人物ERROR1!");
                    return setGameStatus(Game_Status_ERROR);
                }
            }
            if(i == m_nPlayerCount)
                break;
        }



        QByteArray ba = m_pClientsGroupInfo->m_pIOCP->newSendData(0x20);
        QDataStream ds(&ba,QIODevice::ReadWrite);
        ds.device()->seek(ba.size());

        ds << (qint16)GAME_DATA << (qint16)GAME_DATA_TRANSFER_ALLWUJIANGCHOICED
                        << (qint16)m_nPlayerCount << (qint16)1;

        qint32 temp[GAME_MAX_NUM_WUJIANG];
        int j = 0;

        //!!!这里可以修改为所有武将中挑选
        //if(!GetDifferentNumber(0,GAME_MAX_NUM_WUJIANG,temp,count))
        if(!GetDifferentNumber(1,GAME_MAX_NUM_WUJIANG + 1,temp,GAME_MAX_NUM_WUJIANG,sizeof(qint32)))
        {
            emit s_Critical("[!GameServer]随机范围ERROR!");
            return setGameStatus(Game_Status_ERROR);
        }

        for(int i = 0; i < m_nPlayerCount; i++)
        {
            if(m_arrayPlayer[i].m_eJiaoSe == _Player::JiaoSe_Others)       //是 玩家
            {
                //_GameUserData* m_pClientExtraData = (_GameUserData*)(m_pClientsGroupInfo->m_listClients.at(i)->m_pClientExtraData);

            }
            else if(m_arrayPlayer[i].m_eJiaoSe == _Player::JiaoSe_AI)    //是电脑
            {
                //跳过已选的
                while(m_mapWuJiangUsingTimes.contains(temp[j]))
                {
                    j++;

                    if(j >= GAME_MAX_NUM_WUJIANG)
                    {
                        emit s_Critical("[!GameServer]电脑选择人物ERROR!2");
                        return setGameStatus(Game_Status_ERROR);
                    }
                }

                m_mapWuJiangUsingTimes[temp[j]] = 1;

                m_arrayPlayer[i].getWuJiang((_WuJiang::_Value)temp[j]);
            }
            else
            {
                emit s_Critical("[!GameServer]电脑选择人物ERROR3!");
                return setGameStatus(Game_Status_ERROR);
            }

            ds << (qint16)m_arrayPlayer[i].wuJiangValue();
        }

        m_pClientsGroupInfo->m_pIOCP->CorrectDataLength(ba);
        emit s_SendToGroupAllClients(ba, nullptr);
        emit s_Debug("[GameGroup]转发选择武将信息完毕");

        return gameStatus();
    }

    //洗牌ok
    //将qipaidui随机放入paidui中,将所有qipaidui的leixing置为 -1,
    virtual bool Xipai() Q_DECL_OVERRIDE
    {
        emit s_Debug("[GameGroup]洗牌处理中...");
        bool bRet = GameCore::Xipai();
        if(!bRet)
            return false;

        QByteArray ba = m_pClientsGroupInfo->m_pIOCP->newSendData(0x20);
        QDataStream ds(&ba,QIODevice::ReadWrite);
        ds.device()->seek(ba.size());

        ds<<(qint16)GAME_DATA <<
            (qint16)GAME_DATA_TRANSFER_XIPAI <<
            (qint16)m_nPaiDuiShu <<
            (qint16)(sizeof(m_arrayPaiDuiID));
        ds.writeRawData((char*)m_arrayPaiDuiID,sizeof(m_arrayPaiDuiID));

        m_pClientsGroupInfo->m_pIOCP->CorrectDataLength(ba);
        emit s_SendToGroupAllClients(ba, nullptr);
        emit s_Debug("[GameGroup]洗牌发送数据完毕");
        return true;
    }

    virtual _GameButtonValue ChuPai(int player, _GameChuPaiType nType, int nValue, int nParam1 = -1, int nParam2 = -1, QVariant nParam3 = -1, int nInitStep = 0, QString strMsg = "") Q_DECL_OVERRIDE;

    virtual bool WenTi(int player,QString msg,int time) Q_DECL_OVERRIDE;
    virtual int ShowPlayersArea(int player) Q_DECL_OVERRIDE
    {
        return 0;
    }
    virtual int HidePlayersArea() Q_DECL_OVERRIDE
    {
        return 0;
    }

    virtual int ShaiDian() Q_DECL_OVERRIDE;

public:
    quint32         m_unClassID;    //要玩的classID(0为全部)



//框架
public:
    ProducerModel   m_Producer; //生产消费者模式
    qint32          m_nGroupID; //房号(0~999999)

    //与_ClientsGroupInfo互指,一对一
    _ClientsGroupInfo*  m_pClientsGroupInfo;

protected:

private:
};








namespace Ui {
class GameServer;
}

class GameServer : public QWidget
{
    Q_OBJECT

public:
    enum _ServerType
    {
        Type_InfoServer = 0,
        Type_GameServer = 1
    };

public:
    explicit GameServer(QWidget *parent = 0);
    virtual ~GameServer();

public:
//Server信号处理
    void onAccept(_SocketInfo::_SocketContext socketContext);
    void onDisconnect(int type, _SocketInfo::_SocketContext socketContext);
    //Server收到Client的数据 的回调函数
    void onReadyRead(QByteArray baData, quint8 controlByte, _SocketInfo::_SocketContext socketContext);


//服务函数扩展
public:
    bool Start();

    void Stop();
    

public:
//群函数扩展
    //创建一个群(检测groupID可用性),返回<0错误,正确返回groupID
    qint32 CreateGroup(int playerMaxCount, QString password, qint32 groupID)
    {
        if(groupID < 0)
        {
            return groupID;
        }
        if(m_hashNumberGroups.contains(groupID))
        {
            return -1;
        }

        _ClientsGroupInfo *pGroup = m_Server.CreateGroup(playerMaxCount, password);
        if(pGroup != nullptr)
        {
            m_hashNumberGroups.insert(groupID,pGroup);
            ((_GameGroup*)pGroup->m_pClientsGroupExtraData)->m_nGroupID = groupID;
            return groupID;
        }
        else
            return -2;
    }

    //客户状态不对-5;正常返回 m_Server.JoinGroup
    int JoinGroup(_ClientInfo* pClientInfo, _ClientsGroupInfo *pGroup, const QString& password = "")
    {
        _GameUserData *pGameUserData = (_GameUserData*)(pClientInfo->m_pClientExtraData);

        if(pGameUserData->m_GameStatus != _ClientGameStatus::Game_Nothing)
        {
            return -5;
        }
        else
        {
            int ret = m_Server.JoinGroup(pClientInfo, pGroup, password);
            if(ret >= 0)
            {
                pGameUserData->m_GameStatus = _ClientGameStatus::Game_Waiting;
            }
            return ret;
        }
    }
    //加入群,没有找到返回-10;正常返回 JoinGroup
    int JoinGroup(_ClientInfo* pClientInfo, qint32 groupID, const QString& password = "")
    {
        _ClientsGroupInfo *pGroup = m_hashNumberGroups.value(groupID, nullptr);

        if(groupID != 0 && pGroup == nullptr)  //没找到具体房间
            return -10;
        else
            return JoinGroup(pClientInfo, pGroup, password);
    }

    //pClientInfo退出群,groupWillClose是否群已经关闭(如果关闭,则不用再次关闭群,也不用群内群发退群信息;如果为false,会群发,并且关闭空群,)
    //返回ExitGroup(剩余人数)
    int ExitGroup(_ClientInfo *pClientInfo, bool groupWillClose = false);

    //关闭群
    int CloseGroup(_ClientsGroupInfo *pClientsGroupInfo)
    {
        if(pClientsGroupInfo != nullptr)
        {
            //释放房间ExtraData
            qint32 groupID = ((_GameGroup*)pClientsGroupInfo->m_pClientsGroupExtraData)->m_nGroupID;
            if(groupID > 0)
            {
                Debug(_T("[GameServer]移除房间:%1").arg(groupID));
                m_hashNumberGroups.remove(groupID);
            }
            else
            {
                Warning(_T("[!GameServer]WARNING!找不到房间:%1").arg(groupID));
            }

            //每人退群
            QList<_ClientInfo*>::const_iterator ii;
            for(ii = pClientsGroupInfo->m_listClients.constBegin(); ii != pClientsGroupInfo->m_listClients.constEnd(); ++ii)
            {
                ExitGroup(*ii, true);
            }

            //delete (_GameGroup*)(pClientsGroupInfo->m_pClientsGroupExtraData);
            //((_GameGroup*)pClientsGroupInfo->m_pClientsGroupExtraData)->deleteLater();
            //m_poolGameGroup.releaseOneUsing((_GameGroup*)(pClientsGroupInfo->m_pClientsGroupExtraData));
            //Debug("房间释放啦1~");
            //pClientsGroupInfo->m_pClientsGroupExtraData = nullptr;

            m_Server.sendGroupInfoToAllClients(pClientsGroupInfo->m_uuid, 1);
        }
        return m_Server.CloseGroup(pClientsGroupInfo);
    }

    //产生并设置pGroup的 int32的ID(count为位数)
    qint32 CreateGroupHashID(int count)
    {
        if(count <= 0 || count >= 10)
            return -10;

        qint32 number = 0;      //数字
        qint32 tNum = 0;        //用来判断是否循环完毕
        int i = 0;
        int maxNumber = 1;      //最大值(用来求模)

        for(number = 0, i = 0; i < count; i++)
        {
            maxNumber *= 10;
            number *= 10;
            number += qrand() % 10;
        }
        tNum = number;

        while(m_hashNumberGroups.contains(number))  //一直递增找到没有重复的位置
        {
            //QString number = QString("%1").arg(qrand() % 100, 3, 10, QChar('0'))
            //        + QString("%1").arg(qrand() % 100, 3, 10, QChar('0'));
            number = (number + 1) % maxNumber;
            if(number < 0)
                number = 0;
            if(number == tNum)
            {
                number = -11;
                break;
            }
        }

        return number;
    }


//其他
public:
    //信息
    virtual void Message(QString msg);// Q_DECL_OVERRIDE;
    //调试信息
    virtual void Debug(QString msg);// Q_DECL_OVERRIDE;
    //警告信息
    virtual void Warning(QString msg);// Q_DECL_OVERRIDE;
    //错误信息
    virtual void Critical(QString msg);// Q_DECL_OVERRIDE;



//游戏函数
public:
    //扣10分(退出时)
    //返回false不扣分
    bool DeductScore(_ClientInfo *pClientInfo, int score = -100)
    {
        _GameUserData *pGameUserData = (_GameUserData*)(pClientInfo->m_pClientExtraData);

        if(pClientInfo == nullptr)
            return false;
        if(pGameUserData->m_GameStatus != Game_Playing)
        {
            Debug(_T("[GameServer]玩家不扣分:%1").arg(((_GameUserData*)pClientInfo->m_pClientExtraData)->m_strNickName));
            return false;
        }

        int ret = m_DatabaseSwap.updateUserScore(((_GameUserData*)pClientInfo->m_pClientExtraData)->m_unUserGameID, score);
        if(ret >= 0)
        {
            Debug(_T("[GameServer]玩家退出扣分:%1").arg(((_GameUserData*)pClientInfo->m_pClientExtraData)->m_strNickName));
            return true;
        }
        else
        {
            Warning(_T("[!GameServer]WARNING!玩家退出扣分失败:%1(%2)").arg(((_GameUserData*)pClientInfo->m_pClientExtraData)->m_strNickName).arg(ret));
            return false;
        }
    }



//回调函数
public:
    //4个SocketExtraData回调(IOCP回调)
    static void* FUNCTION_CALL_TYPE Fn_IOCP_SetSocketExtraData_Callback()
    {
        qDebug() << "[GameServer]Fn_IOCP_SetSocketExtraData_Callback";

        _ClientInfo *pClientInfo = (_ClientInfo*)Server::Fn_IOCP_SetSocketExtraData_Callback();
        pClientInfo->m_pClientExtraData = new _GameUserData;
        return pClientInfo;
    }

    static void FUNCTION_CALL_TYPE Fn_IOCP_UnsetSocketExtraData_Callback(void *pExtraData)
    {
        if(pExtraData != nullptr)
        {
            qDebug() << "[GameServer]Fn_IOCP_UnsetSocketExtraData_Callback";

            delete (_GameUserData*)(((_ClientInfo*)pExtraData)->m_pClientExtraData);
            Server::Fn_IOCP_UnsetSocketExtraData_Callback(pExtraData);
        }
        else
            qCritical() << "[!GameServer]Fn_IOCP_UnsetSocketExtraData_Callback ERROR!";
    }

    static void FUNCTION_CALL_TYPE Fn_IOCP_Init_SocketExtraData_Callback(void *pExtraData)
    {
        if(pExtraData != nullptr)
        {
            qDebug() << "[GameServer]Fn_IOCP_Init_SocketExtraData_Callback";

            ((_GameUserData*)(((_ClientInfo*)pExtraData)->m_pClientExtraData))->_pool_init();
            Server::Fn_IOCP_Init_SocketExtraData_Callback(pExtraData);
        }
        else
            qCritical() << "[!GameServer]Fn_IOCP_Init_SocketExtraData_Callback ERROR!";
    }

    static void FUNCTION_CALL_TYPE Fn_IOCP_Release_SocketExtraData_Callback(void *pExtraData)
    {
        if(pExtraData != nullptr)
        {
            qDebug() << "[GameServer]Fn_IOCP_Release_SocketExtraData_Callback";

            ((_GameUserData*)(((_ClientInfo*)pExtraData)->m_pClientExtraData))->_pool_release();
            Server::Fn_IOCP_Release_SocketExtraData_Callback(pExtraData);
        }
        else
            qCritical() << "[!GameServer]Fn_IOCP_Release_SocketExtraData_Callback ERROR!";
    }



//4个SocketExtraData回调(Server回调)
    //GroupExtraData的回调函数(池)
    static void* FUNCTION_CALL_TYPE Fn_SetGroupExtraData_Callback()
    {
        qDebug() << "[GameServer]Fn_SetGroupExtraData_Callback";
        return new _GameGroup;
    }

    //GroupExtraData的回调函数(池)
    static void FUNCTION_CALL_TYPE Fn_UnsetGroupExtraData_Callback(void *pGroupExtraData)
    {
        if(pGroupExtraData != nullptr)
        {
            qDebug() << "[GameServer]Fn_UnsetGroupExtraData_Callback";
            delete (_GameGroup*)pGroupExtraData;
        }
        else
            qCritical() << "[!GameServer]UnsetGroupExtraData Callback ERROR!";
    }
    //GroupExtraData的回调函数(池)
    static void FUNCTION_CALL_TYPE Fn_InitGroupExtraData_Callback(void *pGroupExtraData)
    {
        qDebug() << "[GameServer]Fn_InitGroupExtraData_Callback";
        ((_GameGroup*)pGroupExtraData)->_pool_init();
    }

    //GroupExtraData的回调函数(池)
    static void FUNCTION_CALL_TYPE Fn_ReleaseGroupExtraData_Callback(void *pGroupExtraData)
    {
        qDebug() << "[GameServer]Fn_ReleaseGroupExtraData_Callback";
        ((_GameGroup*)pGroupExtraData)->_pool_release();
    }



//数据成员
public:
    //与数据库交互用户信息
    DatabaseSwap m_DatabaseSwap;

    //服务对象
    Server m_Server;

protected:
    QHash<qint32,_ClientsGroupInfo*> m_hashNumberGroups;    //用数字来找房间,同m_mapGroups一样,同时操作(insert和remove)

    //所有客户端 表,!!!其实这里可以用QList,因为pIOCPSocketContext的ExtraData就是pClientInfo!!!
    //???只用contains,QMap速度快还是QList速度快?好像和Server的m_listClients重复了(看哪个快用哪个!)
    QMap<void*,_ClientInfo*> m_mapAllClients;    //pIOCPSocketContext,pClientInfo
    //QList<_ClientInfo*> m_AllClientsList;    //pIOCPSocketContext,pClientInfo

    //QMap<SOCKET,_ClientInfo*> mapClientSocket;

    _ServerType m_ServerType;       //服务器类型(游戏服务器则会:用户强退扣分)
    int m_nRecordUserOnlineLog;     //是否记录 用户登录时间

//私有数据成员
private:
    Ui::GameServer *ui;

};

#endif // GAMESERVER_H
